﻿using System;
using System.ComponentModel;
using System.Linq;

namespace Infrastructure.Lib.Core
{
    [TypeConverter(typeof(RangeConverter))]
    public class Range<T> 
    {
        public T LowerBound { get; set; }
        public T UpperBound { get; set; }
        public bool IncludeLowerBound { get; set; }
        public bool IncludeUpperBound { get; set; }
        public Range() { }
        public Range(string source)
        {
            LowerBound = TryParse(source, true);
            UpperBound = TryParse(source, false);
            IncludeLowerBound = ParseInequality(source, true);
            IncludeUpperBound = ParseInequality(source, false);
        }

        public T TryParse(string source, bool isLeft)
        {
            try
            {
                source = source.Substring(1, source.Length - 2);
                var values = source.Split(',');
                TypeConverter converter = TypeDescriptor.GetConverter(typeof(T));
                bool canConvertFrom = converter.CanConvertFrom(typeof(string));

                if (isLeft)
                {
                    if (values[0] == "$")
                    {
                        var minField = typeof(T).GetField("MinValue");
                        if (minField != null)
                        {
                            return (T)minField.GetValue(null);
                        }
                        throw new ArgumentException("参数格式出错, 该参数不支持[$]");
                    }
                    return (T)converter.ConvertFrom(values[0]);
                }
                else
                {
                    var minField = typeof(T).GetField("MaxValue");
                    if (values[1] == "$")
                    {
                        if (minField != null)
                        {
                            return (T)minField.GetValue(null);
                        }
                        throw new ArgumentException("参数格式出错, 该参数不支持[$]");
                    }
                    return (T)converter.ConvertFrom(values[1]);
                }
            }
            catch (Exception e)
            {
                throw new ArgumentException("区间参数值存在错误", e);
            }
        }

        protected static bool ParseInequality(string source, bool isLeft)
        {
            bool result;
            if (isLeft)
            {
                switch (source.First())
                {
                    case '(': result = false; break;
                    case '[': result = true; break;
                    default: throw new ArgumentException("区间的左不等式表示存在错误, 必需是'('或'['");
                }
            }
            else
            {
                switch (source.Last())
                {
                    case ')': result = false; break;
                    case ']': result = true; break;
                    default: throw new ArgumentException("区间的右不等式表示存在错误, 必需是')'或']'");
                }
            }
            return result;
        }

        public static implicit operator Range<T>(string source)
        {
            return new Range<T>(source);
        }

        public bool IsBetween(T value)
        {
            return true;
            //int lower = LowerBound.CompareTo(value);
            //int upper = UpperBound.CompareTo(value);
            //return (lower > 0 || (IncludeLowerBound && lower == 0))
            //    && (upper < 0 || (IncludeUpperBound && upper == 0));
        }

        public override string ToString()
        {
            return string.Format("[{0},{1}]",this.LowerBound,this.UpperBound);
        }
    }

 
    public class RangeConverter : TypeConverter 
    {

        Type _genericInstanceType;
        Type _innerType;
        TypeConverter _innerTypeConverter;

        public RangeConverter(Type type)
        {
            if (type.IsGenericType && type.GetGenericTypeDefinition() == typeof(Range<>) && type.GetGenericArguments().Length == 1)
            {
                _genericInstanceType = type;
                _innerType = type.GetGenericArguments()[0];
                _innerTypeConverter = TypeDescriptor.GetConverter(_innerType);
            }
            else
            {
                throw new ArgumentException("Incompatible type", "type");
            }
        }
        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == typeof(string)) return true;
            return base.CanConvertFrom(context, sourceType);
        }


        public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
        {
            string input = value as string;

            Type type=  typeof(Range<>);
            
            var makeme = type.MakeGenericType(_innerType);
            object o = Activator.CreateInstance(makeme,input);
            return o;

            //if (input != null) return new Range<>(input);
            //return base.ConvertFrom(context, culture, value);
        }


        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == typeof(Range<>))
                return true;
            return base.CanConvertTo(context, destinationType);
        }



        public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
        {
            if (value != null)
                _innerTypeConverter.ConvertTo(value, destinationType);

            return base.ConvertTo(context, culture, value, destinationType);
        }
    }
    #region
    /*
    //[TypeConverter(typeof(RangeConverter))]
    public class Range<T>
    {
        public Range() { }
        public Range(
            T minValue, 
            T maxValue, 
            Inequality leftInequality, 
            Inequality rightInequality) 
        {
            MinValue = minValue;
            MaxValue = maxValue;
            LeftInequality = leftInequality;
            RightInequality = rightInequality;
        }
        public Range(string source)
        {
            MinValue = TryParse( source, true );
            MaxValue = TryParse( source, false );
            LeftInequality = ParseInequality(source, true);
            RightInequality = ParseInequality(source, false);
        }
        public T TryParse(string source, bool isLeft)
        {
            try
            {
                source = source.Substring(1, source.Length - 2);
                var values = source.Split(',');
                var converter = new Converter<string, T>(ParseValue);
                if (isLeft)
                {
                    return converter(values[0]);
                }
                else
                {
                    return converter(values[1]);
                }
            }
            catch (Exception e)
            {
                throw new ArgumentException("区间参数值存在错误", e);
            }
        }
        public virtual T ParseValue( string source )
        {
            throw new NotImplementedException();
        }

        public T MinValue { get; set; }
        public T MaxValue { get; set; }
        public Inequality LeftInequality { get; set; }
        public Inequality RightInequality { get; set; }

        //public readonly T MinValue;
        //public readonly T MaxValue;
        //public readonly Inequality LeftInequality;
        //public readonly Inequality RightInequality;
        
        public string ToSqlString( string field )
        {
            return string.Format("{0}{1}@{0}MinValue and {0}{2}@{0}MaxValue", field,
                InequalityToSqlString(LeftInequality),
                InequalityToSqlString(RightInequality)
                );
        }

        private string InequalityToSqlString(Inequality inequality)
        {
            string result = string.Empty;
            switch (inequality)
            {
                case Inequality.LessThen :
                    result = "<";break;
                case Inequality.LessThanOrEqual:
                    result = "<="; break;
                case Inequality.GreaterThan:
                    result = ">"; break;
                case Inequality.GreaterThanOrEqual:
                    result = ">="; break;
            }
            return result;
        }

        protected static Inequality ParseInequality(string source, bool isLeft)
        {
            Inequality result ;
            if (isLeft)
            {
                switch (source.First())
                {
                    case '(': result = Inequality.GreaterThan; break;
                    case '[': result = Inequality.GreaterThanOrEqual; break;
                    default: throw new ArgumentException("区间的左不等式表示存在错误, 必需是'('或'['");
                }
            }
            else
            {
                switch (source.Last())
                {
                    case ')': result = Inequality.LessThen; break;
                    case ']': result = Inequality.LessThanOrEqual; break;
                    default: throw new ArgumentException("区间的右不等式表示存在错误, 必需是')'或']'");
                }
            }
            return result;
        }
    }

    public class RangeModelBinder : DefaultModelBinder
    {
        public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
        {
            if (bindingContext.ModelType.BaseType.GetGenericTypeDefinition() == typeof(Range<>))
            {
                var constructor = bindingContext.ModelType
                    .GetConstructors()
                    .Where(t =>
                        t.GetParameters().Any(p => p.Name == "source")
                     )
                    .First();
                var vpResult = bindingContext.ValueProvider.GetValue(bindingContext.ModelName);
                if (vpResult == null) return null;
                return constructor.Invoke((object[])vpResult.RawValue);
            }
            else
              return base.BindModel(controllerContext, bindingContext);
             
        }
    }

    public sealed class FloatRange : Range<float>
    {
        public FloatRange(
            float minValue,
            float maxValue,
            Inequality leftInequality,
            Inequality rightInequality)
            : base(minValue, maxValue, leftInequality, rightInequality) { }
        public FloatRange(string source) : base(source) { }
        public override float ParseValue(string source)
        {
            return float.Parse(source);
        }
        public static implicit operator FloatRange(string source)
        {
            FloatRange result = new FloatRange(source);
            return result;
        }
    }

    public sealed class TimeRange : Range<DateTime>
    {
        public TimeRange(
            DateTime minValue,
            DateTime maxValue,
            Inequality leftInequality,
            Inequality rightInequality)
            : base(minValue, maxValue, leftInequality, rightInequality) { }
        public TimeRange(string source) : base(source) { }
        public override DateTime ParseValue(string source)
        {
            return DateTime.Parse(source);
        }
        public static implicit operator TimeRange(string source)
        {
            TimeRange result = new TimeRange(source);
            return result;
        }
    }

    public sealed class IntRange : Range<int>
    {
        public IntRange(
            int minValue,
            int maxValue,
            Inequality leftInequality,
            Inequality rightInequality)
            : base(minValue, maxValue, leftInequality, rightInequality) { }
        public IntRange(string source) : base(source) { }
        public override int ParseValue(string source)
        {
            return int.Parse(source);
        }
        public static implicit operator IntRange(string source)
        {
            IntRange result = new IntRange(source);
            return result;
        }
    }

    public sealed class DoubleRange : Range<double>
    {
        public DoubleRange(
            double minValue,
            double maxValue,
            Inequality leftInequality,
            Inequality rightInequality)
            : base(minValue, maxValue, leftInequality, rightInequality) { }
        public DoubleRange(string source) : base(source) { }
        public override double ParseValue(string source)
        {
            return double.Parse(source);
        }
        public static implicit operator DoubleRange(string source)
        {
            DoubleRange result = new DoubleRange(source);
            return result;
        }
    }

    /// <summary>
    /// 不等式
    /// </summary>
    public enum Inequality
    {
        //小于 <
        LessThen,
        //小于等于
        LessThanOrEqual,
        //大于
        GreaterThan,
        //大于等于
        GreaterThanOrEqual
    }
    */
    #endregion
}